﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace WhomaShuriken.Core.Utility
{
    /// <summary>
    /// Byte配列(?) 操作用クラス
    /// </summary>
    public class Bytes
    {

        private Bytes() { }//デフォルトコンストラクタの隠蔽

        /// <summary>
        ///複数のオブジェクトを並べて、byte[]に変換する
        /// </summary>
        /// <param name="list">変換対象オブジェクト配列 (byte[] uint ushort String)</param>
        /// <returns></returns>
        public static byte[] Create(params object[] list)
        {
            int len = 0;
            foreach (object o in list)
            {

                if (o == null)
                    continue;

                string typeName = o.GetType().Name;
                if (typeName == "Byte[]")
                {
                    len += ((byte[])o).Length;
                }
                else if (typeName == "Int16" || typeName == "UInt16")
                {
                    len += 2;
                }
                else if (typeName == "Int32" || typeName == "UInt32")
                {
                    len += 4;
                }
                else if (typeName == "Int64" || typeName == "UInt64")
                {
                    len += 8;
                }
                else if (typeName == "Byte")
                {
                    len += 1;
                }
                else if (typeName == "String")
                {
                    byte[] b = Encoding.ASCII.GetBytes((string)o);
                    len += b.Length;
                }
                else
                {
                    //Msg.Show(MSG_KIND.ERROR, "ERROR Bytes.Create() " + typeName);
                }
            }
            byte[] data = new byte[len];
            byte[] tmp = new byte[4];
            int offset = 0;
            foreach (object o in list)
            {

                if (o == null)
                    continue;

                string typeName = o.GetType().Name;
                if (typeName == "Byte[]")
                {
                    Buffer.BlockCopy(((byte[])o), 0, data, offset, ((byte[])o).Length);
                    offset += ((byte[])o).Length;
                }
                else if (typeName == "Int16" || typeName == "UInt16")
                {
                    tmp = BitConverter.GetBytes(Convert.ToUInt16(o));
                    Buffer.BlockCopy(tmp, 0, data, offset, 2);
                    offset += 2;
                }
                else if (typeName == "Int32" || typeName == "UInt32")
                {
                    tmp = BitConverter.GetBytes(Convert.ToUInt32(o));
                    Buffer.BlockCopy(tmp, 0, data, offset, 4);
                    offset += 4;
                }
                else if (typeName == "Int64" || typeName == "UInt64")
                {
                    tmp = BitConverter.GetBytes(Convert.ToUInt64(o));
                    Buffer.BlockCopy(tmp, 0, data, offset, 8);
                    offset += 8;
                }
                else if (typeName == "Byte")
                {
                    data[offset] = (byte)o;
                    offset += 1;
                }
                else if (typeName == "String")
                {
                    byte[] b = Encoding.ASCII.GetBytes((string)o);
                    Buffer.BlockCopy(b, 0, data, offset, b.Length);
                    offset += b.Length;
                }
                else
                {
                    ;
                }
            }
            return data;
        }
        /// <summary>
        /// byte[]を生成する
        /// </summary>
        /// <param name="src"></param>
        /// <param name="len"></param>
        /// <returns></returns>
        public static byte[] Create(byte[] src, int len)
        {
            byte[] dst = new byte[len];
            Buffer.BlockCopy(src, 0, dst, 0, len);
            return dst;
        }

        /// <summary>
        /// bufferの中でtargetが始まる位置を検索する
        /// </summary>
        /// <param name="buffer">検索範囲</param>
        /// <param name="off">検索開始位置</param>
        /// <param name="target">検索対象</param>
        /// <returns></returns>
        public static int IndexOf(byte[] buffer, int off, byte[] target)
        {
            for (int i = off; i + target.Length < buffer.Length; i++)
            {
                bool match = true;
                for (int t = 0; t < target.Length; t++)
                {
                    if (buffer[i + t] != target[t])
                    {
                        match = false;
                        break;
                    }
                }
                if (match)
                {
                    return i;
                }
            }
            return -1;
        }
        /// <summary>
        /// bufferの中でtargetが始まる位置を検索する
        /// </summary>
        /// <param name="buffer">検索範囲</param>
        /// <param name="off">検索開始位置</param>
        /// <param name="endoff">検索終了位置</param>
        /// <param name="target">検索対象</param>
        /// <returns></returns>
        public static int IndexOf(byte[] buffer, int off, int endoff, byte[] target)
        {
            for (int i = off; i + target.Length < endoff; i++)
            {
                bool match = true;
                for (int t = 0; t < target.Length; t++)
                {
                    if (buffer[i + t] != target[t])
                    {
                        match = false;
                        break;
                    }
                }
                if (match)
                {
                    return i;
                }
            }
            return -1;
        }


        /// <summary>
        /// Int16の読み込み
        /// </summary>
        /// <param name="buffer">読み込み対象</param>
        /// <param name="offset">読み込み開始位置</param>
        /// <returns>読み込み結果</returns>
        public static short ReadInt16(byte[] buffer, int offset)
        {
            int off = offset;
            return ReadInt16(buffer, ref off);
        }
        /// <summary>
        /// Int16の読み込み（オフセット移動あり）
        /// </summary>
        /// <param name="buffer">読み込み対象</param>
        /// <param name="offset">読み込み開始位置</param>
        /// <returns>読み込み結果</returns>
        public static short ReadInt16(byte[] buffer, ref int offset)
        {
            offset += 2;
            return BitConverter.ToInt16(buffer, offset - 2);
        }
        /// <summary>
        /// UInt16の読み込み
        /// </summary>
        /// <param name="buffer">読み込み対象</param>
        /// <param name="offset">読み込み開始位置</param>
        /// <returns>読み込み結果</returns>
        public static ushort ReadUInt16(byte[] buffer, int offset)
        {
            int off = offset;
            return ReadUInt16(buffer, ref off);
        }
        /// <summary>
        /// UInt16の読み込み（オフセット移動あり）
        /// </summary>
        /// <param name="buffer">読み込み対象</param>
        /// <param name="offset">読み込み開始位置</param>
        /// <returns>読み込み結果</returns>
        public static ushort ReadUInt16(byte[] buffer, ref int offset)
        {
            offset += 2;
            return BitConverter.ToUInt16(buffer, offset - 2);
        }
       
        /// <summary>
        /// Int32の読み込み
        /// </summary>
        /// <param name="buffer">読み込み対象</param>
        /// <param name="offset">読み込み開始位置</param>
        /// <returns>読み込み結果</returns>
        public static int ReadInt32(byte[] buffer, int offset)
        {
            int off = offset;
            return ReadInt32(buffer, ref off);
        }

        /// <summary>
        /// UInt32の読み込み
        /// </summary>
        /// <param name="buffer">読み込み対象</param>
        /// <param name="offset">読み込み開始位置</param>
        /// <returns>読み込み結果</returns>
        public static int ReadInt32(byte[] buffer, ref int offset)
        {
            offset += 4;
            return BitConverter.ToInt32(buffer, offset - 4);
        }
        /// <summary>
        /// UInt32の読み込み（
        /// </summary>
        /// <param name="buffer">読み込み対象</param>
        /// <param name="offset">読み込み開始位置</param>
        /// <returns>読み込み結果</returns>
        public static uint ReadUInt32(byte[] buffer, int offset)
        {
            int off = offset;
            return ReadUInt32(buffer, ref off);
        }
        /// <summary>
        /// UInt32の読み込み（オフセット移動あり）
        /// </summary>
        /// <param name="buffer">読み込み対象</param>
        /// <param name="offset">読み込み開始位置</param>
        /// <returns>読み込み結果</returns>
        public static uint ReadUInt32(byte[] buffer, ref int offset)
        {
            offset += 4;
            return BitConverter.ToUInt32(buffer, offset - 4);
        }
    }


}
